home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / Direct3D / PointSprites / pointsprites.cpp < prev    next >
C/C++ Source or Header  |  2001-10-31  |  37KB  |  1,114 lines

  1. //-----------------------------------------------------------------------------
  2. // File: PointSprites.cpp
  3. //
  4. // Desc: Sample showing how to use point sprites to do particle effects
  5. //
  6. // Copyright (c) 1997-2001 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include <math.h>
  10. #include <stdio.h>
  11. #include <D3DX8.h>
  12. #include "D3DApp.h"
  13. #include "D3DFont.h"
  14. #include "D3DUtil.h"
  15. #include "DXUtil.h"
  16. #include "resource.h"
  17.  
  18.  
  19.  
  20.  
  21. // Helper function to stuff a FLOAT into a DWORD argument
  22. inline DWORD FtoDW( FLOAT f ) { return *((DWORD*)&f); }
  23.  
  24.  
  25.  
  26.  
  27. //-----------------------------------------------------------------------------
  28. // Custom vertex types
  29. //-----------------------------------------------------------------------------
  30. struct COLORVERTEX
  31. {
  32.     D3DXVECTOR3 v;
  33.     D3DCOLOR    color;
  34.     FLOAT       tu;
  35.     FLOAT       tv;
  36. };
  37.  
  38. #define D3DFVF_COLORVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  39.  
  40.  
  41. struct POINTVERTEX
  42. {
  43.     D3DXVECTOR3 v;
  44.     D3DCOLOR    color;
  45. };
  46.  
  47. #define D3DFVF_POINTVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
  48.  
  49.  
  50.  
  51.  
  52. //-----------------------------------------------------------------------------
  53. // Global structs and data for the ground object
  54. //-----------------------------------------------------------------------------
  55. #define GROUND_WIDTH     256.0f
  56. #define GROUND_HEIGHT    256.0f
  57. #define GROUND_GRIDSIZE  8
  58. #define GROUND_TILE      32
  59. #define GROUND_COLOR     0xcccccccc
  60.  
  61.  
  62.  
  63.  
  64. //-----------------------------------------------------------------------------
  65. // Global data for the particles
  66. //-----------------------------------------------------------------------------
  67. struct PARTICLE
  68. {
  69.     BOOL        m_bSpark;     // Sparks are less energetic particles that
  70.                               // are generated where/when the main particles
  71.                               // hit the ground
  72.  
  73.     D3DXVECTOR3 m_vPos;       // Current position
  74.     D3DXVECTOR3 m_vVel;       // Current velocity
  75.  
  76.     D3DXVECTOR3 m_vPos0;      // Initial position
  77.     D3DXVECTOR3 m_vVel0;      // Initial velocity
  78.     FLOAT       m_fTime0;     // Time of creation
  79.  
  80.     D3DXCOLOR   m_clrDiffuse; // Initial diffuse color
  81.     D3DXCOLOR   m_clrFade;    // Faded diffuse color
  82.     FLOAT       m_fFade;      // Fade progression
  83.  
  84.     PARTICLE*   m_pNext;      // Next particle in list
  85. };
  86.  
  87.  
  88. enum PARTICLE_COLORS { COLOR_WHITE, COLOR_RED, COLOR_GREEN, COLOR_BLUE, NUM_COLORS };
  89.  
  90.  
  91. D3DXCOLOR g_clrColor[NUM_COLORS] =
  92. {
  93.     D3DXCOLOR( 1.0f,   1.0f,   1.0f,   1.0f ),
  94.     D3DXCOLOR( 1.0f,   0.5f,   0.5f,   1.0f ),
  95.     D3DXCOLOR( 0.5f,   1.0f,   0.5f,   1.0f ),
  96.     D3DXCOLOR( 0.125f, 0.5f,   1.0f,   1.0f )
  97. };
  98.  
  99.  
  100. DWORD g_clrColorFade[NUM_COLORS] =
  101. {
  102.     D3DXCOLOR( 1.0f,   0.25f,   0.25f,   1.0f ),
  103.     D3DXCOLOR( 1.0f,   0.25f,   0.25f,   1.0f ),
  104.     D3DXCOLOR( 0.25f,  0.75f,   0.25f,   1.0f ),
  105.     D3DXCOLOR( 0.125f, 0.25f,   0.75f,   1.0f )
  106. };
  107.  
  108.  
  109.  
  110.  
  111. //-----------------------------------------------------------------------------
  112. // Name:
  113. // Desc:
  114. //-----------------------------------------------------------------------------
  115. class CParticleSystem
  116. {
  117. protected:
  118.     FLOAT     m_fRadius;
  119.  
  120.     DWORD     m_dwBase;
  121.     DWORD     m_dwFlush;
  122.     DWORD     m_dwDiscard;
  123.  
  124.     DWORD     m_dwParticles;
  125.     DWORD     m_dwParticlesLim;
  126.     PARTICLE* m_pParticles;
  127.     PARTICLE* m_pParticlesFree;
  128.  
  129.     // Geometry
  130.     LPDIRECT3DVERTEXBUFFER8 m_pVB;
  131.  
  132. public:
  133.     CParticleSystem( DWORD dwFlush, DWORD dwDiscard, FLOAT fRadius );
  134.    ~CParticleSystem();
  135.  
  136.     HRESULT RestoreDeviceObjects( LPDIRECT3DDEVICE8 pd3dDevice );
  137.     HRESULT InvalidateDeviceObjects();
  138.  
  139.     HRESULT Update( FLOAT fSecsPerFrame, DWORD dwNumParticlesToEmit,
  140.                     const D3DXCOLOR &dwEmitColor, const D3DXCOLOR &dwFadeColor,
  141.                     FLOAT fEmitVel, D3DXVECTOR3 vPosition );
  142.  
  143.     HRESULT Render( LPDIRECT3DDEVICE8 pd3dDevice );
  144. };
  145.  
  146.  
  147.  
  148.  
  149. //-----------------------------------------------------------------------------
  150. // Name: class CMyD3DApplication
  151. // Desc: Application class. The base class (CD3DApplication) provides the 
  152. //       generic functionality needed in all Direct3D samples. CMyD3DApplication 
  153. //       adds functionality specific to this sample program.
  154. //-----------------------------------------------------------------------------
  155. class CMyD3DApplication : public CD3DApplication
  156. {
  157.     CD3DFont*          m_pFont;
  158.     CD3DFont*          m_pFontSmall;
  159.  
  160.     // Ground stuff
  161.     LPDIRECT3DTEXTURE8 m_pGroundTexture;
  162.     D3DXPLANE          m_planeGround;
  163.  
  164.     LPDIRECT3DVERTEXBUFFER8 m_pGroundVB;
  165.     LPDIRECT3DINDEXBUFFER8  m_pGroundIB;
  166.     DWORD              m_dwNumGroundIndices;
  167.     DWORD              m_dwNumGroundVertices;
  168.  
  169.     // Particle stuff
  170.     LPDIRECT3DTEXTURE8 m_pParticleTexture;
  171.     CParticleSystem*   m_pParticleSystem;
  172.     DWORD              m_dwNumParticlesToEmit;
  173.     DWORD              m_dwParticleColor;
  174.     BOOL               m_bAnimateEmitter;
  175.  
  176.     BYTE               m_bKey[256];
  177.     BOOL               m_bDrawReflection;
  178.     BOOL               m_bCanDoAlphaBlend;
  179.     BOOL               m_bDrawHelp;
  180.  
  181.     // Variables for determining view position
  182.     D3DXVECTOR3        m_vPosition;
  183.     D3DXVECTOR3        m_vVelocity;
  184.     FLOAT              m_fYaw;
  185.     FLOAT              m_fYawVelocity;
  186.     FLOAT              m_fPitch;
  187.     FLOAT              m_fPitchVelocity;
  188.     D3DXMATRIX         m_matView;
  189.     D3DXMATRIX         m_matOrientation;
  190.  
  191.     HRESULT ConfirmDevice( D3DCAPS8*, DWORD, D3DFORMAT );
  192.  
  193. protected:
  194.     HRESULT OneTimeSceneInit();
  195.     HRESULT InitDeviceObjects();
  196.     HRESULT RestoreDeviceObjects();
  197.     HRESULT InvalidateDeviceObjects();
  198.     HRESULT DeleteDeviceObjects();
  199.     HRESULT Render();
  200.     HRESULT FrameMove();
  201.     HRESULT FinalCleanup();
  202.     VOID    UpdateCamera();
  203.  
  204. public:
  205.     LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  206.     CMyD3DApplication();
  207. };
  208.  
  209.  
  210.  
  211.  
  212. //-----------------------------------------------------------------------------
  213. // Name: WinMain()
  214. // Desc: Entry point to the program. Initializes everything, and goes into a
  215. //       message-processing loop. Idle time is used to render the scene.
  216. //-----------------------------------------------------------------------------
  217. INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
  218. {
  219.     CMyD3DApplication d3dApp;
  220.  
  221.     if( FAILED( d3dApp.Create( hInst ) ) )
  222.         return 0;
  223.  
  224.     return d3dApp.Run();
  225. }
  226.  
  227.  
  228.  
  229.  
  230. //-----------------------------------------------------------------------------
  231. // Name: CMyD3DApplication()
  232. // Desc: Application constructor. Sets attributes for the app.
  233. //-----------------------------------------------------------------------------
  234. CMyD3DApplication::CMyD3DApplication()
  235. {
  236.     m_strWindowTitle    = _T("PointSprites: Using particle effects");
  237.     m_bUseDepthBuffer   = TRUE;
  238.  
  239.     m_pFont                = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
  240.     m_pFontSmall           = new CD3DFont( _T("Arial"),  9, D3DFONT_BOLD );
  241.  
  242.     m_pParticleSystem      = new CParticleSystem( 512, 2048, 0.03f );
  243.     m_pParticleTexture     = NULL;
  244.     m_dwNumParticlesToEmit = 10;
  245.     m_bAnimateEmitter      = FALSE;
  246.     m_dwParticleColor      = COLOR_WHITE;
  247.  
  248.     m_pGroundTexture       = NULL;
  249.     m_dwNumGroundVertices  = (GROUND_GRIDSIZE + 1) * (GROUND_GRIDSIZE + 1);
  250.     m_dwNumGroundIndices   = (GROUND_GRIDSIZE * GROUND_GRIDSIZE) * 6;
  251.     m_pGroundVB            = NULL;
  252.     m_pGroundIB            = NULL;
  253.     m_planeGround          = D3DXPLANE( 0.0f, 1.0f, 0.0f, 0.0f );
  254.  
  255.     m_bDrawReflection      = FALSE;
  256.     m_bCanDoAlphaBlend     = FALSE;
  257.     m_bDrawHelp            = FALSE;
  258.  
  259.     ZeroMemory( m_bKey, 256 );
  260.     m_vPosition      = D3DXVECTOR3( 0.0f, 3.0f,-4.0f );
  261.     m_vVelocity      = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  262.     m_fYaw           = 0.03f;
  263.     m_fYawVelocity   = 0.0f;
  264.     m_fPitch         = 0.5f;
  265.     m_fPitchVelocity = 0.0f;
  266.     D3DXMatrixTranslation( &m_matView, 0.0f, 0.0f, 10.0f );
  267.     D3DXMatrixTranslation( &m_matOrientation, 0.0f, 0.0f, 0.0f );
  268. }
  269.  
  270.  
  271.  
  272.  
  273. //-----------------------------------------------------------------------------
  274. // Name: OneTimeSceneInit()
  275. // Desc: Called during initial app startup, this function performs all the
  276. //       permanent initialization.
  277. //-----------------------------------------------------------------------------
  278. HRESULT CMyD3DApplication::OneTimeSceneInit()
  279. {
  280.     return S_OK;
  281. }
  282.  
  283.  
  284.  
  285.  
  286. //-----------------------------------------------------------------------------
  287. // Name: FrameMove()
  288. // Desc: Called once per frame, the call is the entry point for animating
  289. //       the scene.
  290. //-----------------------------------------------------------------------------
  291. HRESULT CMyD3DApplication::FrameMove()
  292. {
  293.     // Slow things down for the REF device
  294.     if( m_d3dCaps.DeviceType == D3DDEVTYPE_REF )
  295.         m_fElapsedTime = 0.05f;
  296.  
  297.     // Determine emitter position
  298.     D3DXVECTOR3 vEmitterPostion( 0.0f, 0.0f, 0.f );
  299.     if( m_bAnimateEmitter )
  300.         vEmitterPostion = D3DXVECTOR3( 3*sinf(m_fTime), 0.0f, 3*cosf(m_fTime) );
  301.  
  302.     // Update particle system
  303.     m_pParticleSystem->Update( m_fElapsedTime, m_dwNumParticlesToEmit,
  304.                                g_clrColor[m_dwParticleColor],
  305.                                g_clrColorFade[m_dwParticleColor], 8.0f,
  306.                                vEmitterPostion );
  307.  
  308.     return S_OK;
  309. }
  310.  
  311.  
  312.  
  313.  
  314. //-----------------------------------------------------------------------------
  315. // Name: Render()
  316. // Desc: Called once per frame, the call is the entry point for 3d
  317. //       rendering. This function sets up render states, clears the
  318. //       viewport, and renders the scene.
  319. //-----------------------------------------------------------------------------
  320. HRESULT CMyD3DApplication::Render()
  321. {
  322.     // Update the camera here rather than in FrameMove() so you can
  323.     // move the camera even when the scene is paused
  324.     UpdateCamera();
  325.  
  326.     if( FAILED( m_pd3dDevice->BeginScene() ) )
  327.         return S_OK;
  328.  
  329.     // Clear the viewport
  330.     m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 
  331.                          0x00000000, 1.0f, 0L );
  332.  
  333.     // Draw reflection of particles
  334.     if( m_bDrawReflection )
  335.     {
  336.         D3DXMATRIX matReflectedView;
  337.         D3DXMatrixReflect( &matReflectedView, &m_planeGround );
  338.         D3DXMatrixMultiply( &matReflectedView, &matReflectedView, &m_matView );        
  339.     
  340.         m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
  341.         m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  342.         m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
  343.         m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  344.  
  345.         m_pd3dDevice->SetTransform( D3DTS_VIEW, &matReflectedView );
  346.         m_pd3dDevice->SetTexture( 0, m_pParticleTexture );
  347.         m_pParticleSystem->Render( m_pd3dDevice );
  348.  
  349.         m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
  350.         m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
  351.     }
  352.  
  353.  
  354.     // Draw the ground
  355.     if( m_bDrawReflection )
  356.     {
  357.         m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  358.         m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
  359.         m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  360.     }
  361.  
  362.     m_pd3dDevice->SetTransform( D3DTS_VIEW, &m_matView );
  363.     m_pd3dDevice->SetTexture( 0, m_pGroundTexture );
  364.     m_pd3dDevice->SetVertexShader( D3DFVF_COLORVERTEX );
  365.     m_pd3dDevice->SetStreamSource( 0, m_pGroundVB, sizeof(COLORVERTEX) );
  366.     m_pd3dDevice->SetIndices( m_pGroundIB, 0L );
  367.     m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, m_dwNumGroundVertices, 0, m_dwNumGroundIndices/3 );
  368.  
  369.  
  370.     // Draw particles
  371.     m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
  372.     m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  373.     m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
  374.     m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  375.  
  376.     m_pd3dDevice->SetTexture(0, m_pParticleTexture );
  377.     m_pParticleSystem->Render( m_pd3dDevice );
  378.  
  379.     m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
  380.     m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
  381.  
  382.  
  383.     // Output statistics
  384.     m_pFont->DrawText( 2,  0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats );
  385.     m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
  386.  
  387.  
  388.     // Draw help
  389.     if( m_bDrawHelp )
  390.     {
  391.         m_pFontSmall->DrawText( 2, 40, 0xffffffff,
  392.                                 _T("Keyboard controls:") );
  393.         m_pFontSmall->DrawText( 20, 60, 0xffffffff,
  394.                                 _T("Move\nTurn\nPitch\nSlide\n\nHelp\n"
  395.                                    "Change device\nAnimate emitter\n"
  396.                                    "Change color\n\nToggle reflection\n"
  397.                                    "Exit") );
  398.         m_pFontSmall->DrawText( 160, 60, 0xffffffff,
  399.                                 _T("W,S\nE,Q\nA,Z\nArrow keys\n\n"
  400.                                    "F1\nF2\nF3\nF4\n\nR\nEsc") );
  401.     }
  402.     else
  403.         m_pFontSmall->DrawText( 2, 40, 0xffffffff,
  404.                                 _T("Press F1 for help") );
  405.  
  406.     
  407.     // End the scene.
  408.     m_pd3dDevice->EndScene();
  409.     return S_OK;
  410. }
  411.  
  412.  
  413.  
  414.  
  415. //-----------------------------------------------------------------------------
  416. // Name: UpdateCamera()
  417. // Desc: 
  418. //-----------------------------------------------------------------------------
  419. VOID CMyD3DApplication::UpdateCamera()
  420. {
  421.     FLOAT fElapsedTime;
  422.  
  423.     if( m_fElapsedTime > 0.0f )
  424.         fElapsedTime = m_fElapsedTime;
  425.     else
  426.         fElapsedTime = 0.05f;
  427.  
  428.     FLOAT fSpeed        = 3.0f*fElapsedTime;
  429.     FLOAT fAngularSpeed = 1.0f*fElapsedTime;
  430.  
  431.     // De-accelerate the camera movement (for smooth motion)
  432.     m_vVelocity      *= 0.9f;
  433.     m_fYawVelocity   *= 0.9f;
  434.     m_fPitchVelocity *= 0.9f;
  435.  
  436.     // Process keyboard input
  437.     if( m_bKey[VK_RIGHT] )    m_vVelocity.x    += fSpeed; // Slide Right
  438.     if( m_bKey[VK_LEFT] )     m_vVelocity.x    -= fSpeed; // Slide Left
  439.     if( m_bKey[VK_UP] )       m_vVelocity.y    += fSpeed; // Slide Up
  440.     if( m_bKey[VK_DOWN] )     m_vVelocity.y    -= fSpeed; // Slide Down
  441.     if( m_bKey['W'] )         m_vVelocity.z    += fSpeed; // Move Forward
  442.     if( m_bKey['S'] )         m_vVelocity.z    -= fSpeed; // Move Backward
  443.     if( m_bKey['E'] )         m_fYawVelocity   += fSpeed; // Turn Right
  444.     if( m_bKey['Q'] )         m_fYawVelocity   -= fSpeed; // Turn Left
  445.     if( m_bKey['Z'] )         m_fPitchVelocity += fSpeed; // Turn Down
  446.     if( m_bKey['A'] )         m_fPitchVelocity -= fSpeed; // Turn Up
  447.     if( m_bKey[VK_ADD] )      if( m_dwNumParticlesToEmit < 10 ) m_dwNumParticlesToEmit++;
  448.     if( m_bKey[VK_SUBTRACT] ) if( m_dwNumParticlesToEmit > 0 )  m_dwNumParticlesToEmit--;
  449.  
  450.     // Update the position vector
  451.     D3DXVECTOR3 vT = m_vVelocity * fSpeed;
  452.     D3DXVec3TransformNormal( &vT, &vT, &m_matOrientation );
  453.     m_vPosition += vT;
  454.     if( m_vPosition.y < 1.0f )
  455.         m_vPosition.y = 1.0f;
  456.  
  457.     // Update the yaw-pitch-rotation vector
  458.     m_fYaw   += fAngularSpeed * m_fYawVelocity;
  459.     m_fPitch += fAngularSpeed * m_fPitchVelocity;
  460.     if( m_fPitch < 0.0f )      m_fPitch = 0.0f;
  461.     if( m_fPitch > D3DX_PI/2 ) m_fPitch = D3DX_PI/2;
  462.  
  463.     // Set the view matrix
  464.     D3DXQUATERNION qR;
  465.     D3DXQuaternionRotationYawPitchRoll( &qR, m_fYaw, m_fPitch, 0.0f );
  466.     D3DXMatrixAffineTransformation( &m_matOrientation, 1.25f, NULL, &qR, &m_vPosition );
  467.     D3DXMatrixInverse( &m_matView, NULL, &m_matOrientation );
  468. }
  469.  
  470.  
  471. //-----------------------------------------------------------------------------
  472. // Name: InitDeviceObjects()
  473. // Desc: Initialize scene objects.
  474. //-----------------------------------------------------------------------------
  475. HRESULT CMyD3DApplication::InitDeviceObjects()
  476. {
  477.     HRESULT hr;
  478.  
  479.     // Create textures
  480.     if( FAILED( D3DUtil_CreateTexture( m_pd3dDevice, _T("Ground2.bmp"),
  481.                                        &m_pGroundTexture ) ) )
  482.         return D3DAPPERR_MEDIANOTFOUND;
  483.  
  484.     if( FAILED( D3DUtil_CreateTexture( m_pd3dDevice, _T("Particle.bmp"),
  485.                                        &m_pParticleTexture ) ) )
  486.         return D3DAPPERR_MEDIANOTFOUND;
  487.  
  488.     // Set up the fonts and textures
  489.     m_pFont->InitDeviceObjects( m_pd3dDevice );
  490.     m_pFontSmall->InitDeviceObjects( m_pd3dDevice );
  491.  
  492.     // Check if we can do the reflection effect
  493.     m_bCanDoAlphaBlend = (m_d3dCaps.SrcBlendCaps & D3DPBLENDCAPS_SRCALPHA) &&
  494.                          (m_d3dCaps.DestBlendCaps & D3DPBLENDCAPS_INVSRCALPHA);
  495.  
  496.     if( m_bCanDoAlphaBlend )
  497.         m_bDrawReflection = TRUE;
  498.  
  499.     // Create ground object
  500.     {
  501.         // Create vertex buffer for ground object
  502.         hr = m_pd3dDevice->CreateVertexBuffer( m_dwNumGroundVertices*sizeof(COLORVERTEX),
  503.                                                D3DUSAGE_WRITEONLY, D3DFVF_COLORVERTEX,
  504.                                                D3DPOOL_MANAGED, &m_pGroundVB );
  505.         if( FAILED(hr) )
  506.             return E_FAIL;
  507.  
  508.         // Fill vertex buffer
  509.         COLORVERTEX* pVertices;
  510.         if( FAILED( m_pGroundVB->Lock( 0, 0, (BYTE**)&pVertices, NULL ) ) )
  511.             return hr;
  512.  
  513.         // Fill in vertices
  514.         for( DWORD zz = 0; zz <= GROUND_GRIDSIZE; zz++ )
  515.         {
  516.             for( DWORD xx = 0; xx <= GROUND_GRIDSIZE; xx++ )
  517.             {
  518.                 pVertices->v.x   = GROUND_WIDTH * (xx/(FLOAT)GROUND_GRIDSIZE-0.5f);
  519.                 pVertices->v.y   = 0.0f;
  520.                 pVertices->v.z   = GROUND_HEIGHT * (zz/(FLOAT)GROUND_GRIDSIZE-0.5f);
  521.                 pVertices->color = GROUND_COLOR;
  522.                 pVertices->tu    = xx*GROUND_TILE/(FLOAT)GROUND_GRIDSIZE;
  523.                 pVertices->tv    = zz*GROUND_TILE/(FLOAT)GROUND_GRIDSIZE;
  524.                 pVertices++;
  525.             }
  526.         }
  527.  
  528.         m_pGroundVB->Unlock();
  529.  
  530.         // Create the index buffer
  531.         WORD* pIndices;
  532.         hr = m_pd3dDevice->CreateIndexBuffer( m_dwNumGroundIndices*sizeof(WORD),
  533.                                               D3DUSAGE_WRITEONLY,
  534.                                               D3DFMT_INDEX16, D3DPOOL_MANAGED,
  535.                                               &m_pGroundIB );
  536.         if( FAILED(hr) )
  537.             return E_FAIL;
  538.  
  539.         // Fill the index buffer
  540.         m_pGroundIB->Lock( 0, m_dwNumGroundIndices*sizeof(WORD), (BYTE**)&pIndices, 0 );
  541.         if( FAILED(hr) )
  542.             return E_FAIL;
  543.  
  544.         // Fill in indices
  545.         for( DWORD z = 0; z < GROUND_GRIDSIZE; z++ )
  546.         {
  547.             for( DWORD x = 0; x < GROUND_GRIDSIZE; x++ )
  548.             {
  549.                 DWORD vtx = x + z * (GROUND_GRIDSIZE+1);
  550.                 *pIndices++ = (WORD)( vtx + 1 );
  551.                 *pIndices++ = (WORD)( vtx + 0 );
  552.                 *pIndices++ = (WORD)( vtx + 0 + (GROUND_GRIDSIZE+1) );
  553.                 *pIndices++ = (WORD)( vtx + 1 );
  554.                 *pIndices++ = (WORD)( vtx + 0 + (GROUND_GRIDSIZE+1) );
  555.                 *pIndices++ = (WORD)( vtx + 1 + (GROUND_GRIDSIZE+1) );
  556.             }
  557.         }
  558.  
  559.         m_pGroundIB->Unlock();
  560.     }
  561.  
  562.     return S_OK;
  563. }
  564.  
  565.  
  566.  
  567.  
  568. //-----------------------------------------------------------------------------
  569. // Name: RestoreDeviceObjects()
  570. // Desc:
  571. //-----------------------------------------------------------------------------
  572. HRESULT CMyD3DApplication::RestoreDeviceObjects()
  573. {
  574.     HRESULT hr;
  575.  
  576.     m_pFont->RestoreDeviceObjects();
  577.     m_pFontSmall->RestoreDeviceObjects();
  578.  
  579.     // Set the world matrix
  580.     D3DXMATRIX matWorld;
  581.     D3DXMatrixIdentity( &matWorld );
  582.     m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  583.  
  584.     // Set projection matrix
  585.     D3DXMATRIX matProj;
  586.     FLOAT fAspect = ((FLOAT)m_d3dsdBackBuffer.Width) / m_d3dsdBackBuffer.Height;
  587.     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, 0.1f, 100.0f );
  588.     m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  589.  
  590.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  591.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  592.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  593.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
  594.     m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
  595.     m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );
  596.  
  597.     m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_ONE );
  598.     m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  599.     m_pd3dDevice->SetRenderState( D3DRS_LIGHTING,  FALSE );
  600.     m_pd3dDevice->SetRenderState( D3DRS_CULLMODE,  D3DCULL_CCW );
  601.     m_pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT );
  602.  
  603.     // Initialize the particle system
  604.     if( FAILED( hr = m_pParticleSystem->RestoreDeviceObjects( m_pd3dDevice ) ) )
  605.         return hr;
  606.  
  607.     return S_OK;
  608. }
  609.  
  610.  
  611.  
  612.  
  613. //-----------------------------------------------------------------------------
  614. // Name: InvalidateDeviceObjects()
  615. // Desc:
  616. //-----------------------------------------------------------------------------
  617. HRESULT CMyD3DApplication::InvalidateDeviceObjects()
  618. {
  619.     m_pFont->InvalidateDeviceObjects();
  620.     m_pFontSmall->InvalidateDeviceObjects();
  621.     m_pParticleSystem->InvalidateDeviceObjects();
  622.  
  623.     return S_OK;
  624. }
  625.  
  626.  
  627.  
  628.  
  629. //-----------------------------------------------------------------------------
  630. // Name: DeleteDeviceObjects()
  631. // Desc: Called when the app is exiting, or the device is being changed,
  632. //       this function deletes any device dependent objects.
  633. //-----------------------------------------------------------------------------
  634. HRESULT CMyD3DApplication::DeleteDeviceObjects()
  635. {
  636.     m_pFont->DeleteDeviceObjects();
  637.     m_pFontSmall->DeleteDeviceObjects();
  638.  
  639.     SAFE_RELEASE( m_pGroundTexture );
  640.     SAFE_RELEASE( m_pParticleTexture );
  641.  
  642.     SAFE_RELEASE( m_pGroundVB );
  643.     SAFE_RELEASE( m_pGroundIB );
  644.  
  645.     return S_OK;
  646. }
  647.  
  648.  
  649.  
  650.  
  651. //-----------------------------------------------------------------------------
  652. // Name: FinalCleanup()
  653. // Desc: Called before the app exits, this function gives the app the chance
  654. //       to cleanup after itself.
  655. //-----------------------------------------------------------------------------
  656. HRESULT CMyD3DApplication::FinalCleanup()
  657. {
  658.     SAFE_DELETE( m_pFont );
  659.     SAFE_DELETE( m_pFontSmall );
  660.     SAFE_DELETE( m_pGroundTexture );
  661.     SAFE_DELETE( m_pParticleTexture );
  662.     SAFE_DELETE( m_pParticleSystem );
  663.  
  664.     return S_OK;
  665. }
  666.  
  667.  
  668.  
  669.  
  670. //-----------------------------------------------------------------------------
  671. // Name: ConfirmDevice()
  672. // Desc: Called during device intialization, this code checks the device
  673. //       for some minimum set of capabilities
  674. //-----------------------------------------------------------------------------
  675. HRESULT CMyD3DApplication::ConfirmDevice( D3DCAPS8* pCaps, DWORD dwBehavior,
  676.                                           D3DFORMAT Format )
  677. {
  678.     // Make sure device can do ONE:ONE alphablending
  679.     if( 0 == ( pCaps->SrcBlendCaps & D3DPBLENDCAPS_ONE ) )
  680.         return E_FAIL;
  681.     if( 0 == ( pCaps->DestBlendCaps & D3DPBLENDCAPS_ONE ) )
  682.         return E_FAIL;
  683.  
  684.     // Make sure HW TnL devices can do point sprites
  685.     if( (dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING ) ||
  686.         (dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING ) )
  687.     {
  688.         if( pCaps->MaxPointSize <= 1.0f )
  689.             return E_FAIL;
  690.     }
  691.  
  692.     return S_OK;
  693. }
  694.  
  695.  
  696.  
  697.  
  698. //-----------------------------------------------------------------------------
  699. // Name: MsgProc()
  700. // Desc: Message proc function to handle key and menu input
  701. //-----------------------------------------------------------------------------
  702. LRESULT CMyD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
  703.                                     LPARAM lParam )
  704. {
  705.     // Record key presses
  706.     if( WM_KEYDOWN == uMsg )
  707.     {
  708.         m_bKey[wParam] = 1;
  709.     }
  710.  
  711.     // Perform commands when keys are rleased
  712.     if( WM_KEYUP == uMsg )
  713.     {
  714.         m_bKey[wParam] = 0;
  715.  
  716.         switch( wParam )
  717.         {
  718.             case VK_F1:
  719.                 m_bDrawHelp = !m_bDrawHelp;
  720.                 return 1;
  721.  
  722.             case 'R':
  723.                 if( m_bCanDoAlphaBlend )
  724.                     m_bDrawReflection = !m_bDrawReflection;
  725.                 break;
  726.  
  727.             case VK_F3:
  728.                 m_bAnimateEmitter = !m_bAnimateEmitter;
  729.                 break;
  730.  
  731.             case VK_F4:
  732.                 if( ++m_dwParticleColor >= NUM_COLORS )
  733.                     m_dwParticleColor = COLOR_WHITE;
  734.                 break;
  735.         }
  736.     }
  737.  
  738.     return CD3DApplication::MsgProc( hWnd, uMsg, wParam, lParam );
  739. }
  740.  
  741.  
  742.  
  743.  
  744.  
  745. //-----------------------------------------------------------------------------
  746. // Name:
  747. // Desc:
  748. //-----------------------------------------------------------------------------
  749. CParticleSystem::CParticleSystem( DWORD dwFlush, DWORD dwDiscard, float fRadius )
  750. {
  751.     m_fRadius        = fRadius;
  752.  
  753.     m_dwBase         = dwDiscard;
  754.     m_dwFlush        = dwFlush;
  755.     m_dwDiscard      = dwDiscard;
  756.  
  757.     m_dwParticles    = 0;
  758.     m_dwParticlesLim = 2048;
  759.  
  760.     m_pParticles     = NULL;
  761.     m_pParticlesFree = NULL;
  762.     m_pVB            = NULL;
  763. }
  764.  
  765.  
  766.  
  767.  
  768. //-----------------------------------------------------------------------------
  769. // Name:
  770. // Desc:
  771. //-----------------------------------------------------------------------------
  772. CParticleSystem::~CParticleSystem()
  773. {
  774.     InvalidateDeviceObjects();
  775.  
  776.     while( m_pParticles )
  777.     {
  778.         PARTICLE* pSpark = m_pParticles;
  779.         m_pParticles = pSpark->m_pNext;
  780.         delete pSpark;
  781.     }
  782.  
  783.     while( m_pParticlesFree )
  784.     {
  785.         PARTICLE *pSpark = m_pParticlesFree;
  786.         m_pParticlesFree = pSpark->m_pNext;
  787.         delete pSpark;
  788.     }
  789. }
  790.  
  791.  
  792.  
  793.  
  794. //-----------------------------------------------------------------------------
  795. // Name:
  796. // Desc:
  797. //-----------------------------------------------------------------------------
  798. HRESULT CParticleSystem::RestoreDeviceObjects( LPDIRECT3DDEVICE8 pd3dDevice )
  799. {
  800.     HRESULT hr;
  801.  
  802.     // Create a vertex buffer for the particle system.  The size of this buffer
  803.     // does not relate to the number of particles that exist.  Rather, the
  804.     // buffer is used as a communication channel with the device.. we fill in 
  805.     // a bit, and tell the device to draw.  While the device is drawing, we
  806.     // fill in the next bit using NOOVERWRITE.  We continue doing this until 
  807.     // we run out of vertex buffer space, and are forced to DISCARD the buffer
  808.     // and start over at the beginning.
  809.  
  810.     if(FAILED(hr = pd3dDevice->CreateVertexBuffer( m_dwDiscard * 
  811.         sizeof(POINTVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY | D3DUSAGE_POINTS, 
  812.         D3DFVF_POINTVERTEX, D3DPOOL_DEFAULT, &m_pVB )))
  813.     {
  814.         return E_FAIL;
  815.     }
  816.  
  817.     return S_OK;
  818. }
  819.  
  820.  
  821.  
  822.  
  823. //-----------------------------------------------------------------------------
  824. // Name:
  825. // Desc:
  826. //-----------------------------------------------------------------------------
  827. HRESULT CParticleSystem::InvalidateDeviceObjects()
  828. {
  829.     SAFE_RELEASE( m_pVB );
  830.  
  831.     return S_OK;
  832. }
  833.  
  834.  
  835.  
  836.  
  837. //-----------------------------------------------------------------------------
  838. // Name:
  839. // Desc:
  840. //-----------------------------------------------------------------------------
  841. HRESULT CParticleSystem::Update( FLOAT fSecsPerFrame, DWORD dwNumParticlesToEmit,
  842.                                  const D3DXCOLOR &clrEmitColor,
  843.                                  const D3DXCOLOR &clrFadeColor, float fEmitVel,
  844.                                  D3DXVECTOR3 vPosition )
  845. {
  846.     PARTICLE *pParticle, **ppParticle;
  847.     static float fTime = 0.0f;
  848.     fTime += fSecsPerFrame;
  849.  
  850.     ppParticle = &m_pParticles;
  851.  
  852.     while( *ppParticle )
  853.     {
  854.         pParticle = *ppParticle;
  855.  
  856.         // Calculate new position
  857.         float fT = fTime - pParticle->m_fTime0;
  858.         float fGravity;
  859.  
  860.         if( pParticle->m_bSpark )
  861.         {
  862.             fGravity = -5.0f;
  863.             pParticle->m_fFade -= fSecsPerFrame * 2.25f;
  864.         }
  865.         else
  866.         {
  867.             fGravity = -9.8f;
  868.             pParticle->m_fFade -= fSecsPerFrame * 0.25f;
  869.         }
  870.  
  871.         pParticle->m_vPos    = pParticle->m_vVel0 * fT + pParticle->m_vPos0;
  872.         pParticle->m_vPos.y += (0.5f * fGravity) * (fT * fT);
  873.         pParticle->m_vVel.y  = pParticle->m_vVel0.y + fGravity * fT;
  874.  
  875.         if( pParticle->m_fFade < 0.0f )
  876.             pParticle->m_fFade = 0.0f;
  877.  
  878.         // Kill old particles
  879.         if( pParticle->m_vPos.y < m_fRadius ||
  880.             pParticle->m_bSpark && pParticle->m_fFade <= 0.0f )
  881.         {
  882.             // Emit sparks
  883.             if( !pParticle->m_bSpark )
  884.             {
  885.                 for( int i=0; i<4; i++ )
  886.                 {
  887.                     PARTICLE *pSpark;
  888.  
  889.                     if( m_pParticlesFree )
  890.                     {
  891.                         pSpark = m_pParticlesFree;
  892.                         m_pParticlesFree = pSpark->m_pNext;
  893.                     }
  894.                     else
  895.                     {
  896.                         if( NULL == ( pSpark = new PARTICLE ) )
  897.                             return E_OUTOFMEMORY;
  898.                     }
  899.  
  900.                     pSpark->m_pNext = pParticle->m_pNext;
  901.                     pParticle->m_pNext = pSpark;
  902.  
  903.                     pSpark->m_bSpark  = TRUE;
  904.                     pSpark->m_vPos0   = pParticle->m_vPos;
  905.                     pSpark->m_vPos0.y = m_fRadius;
  906.  
  907.                     FLOAT fRand1 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 2.00f;
  908.                     FLOAT fRand2 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 0.25f;
  909.  
  910.                     pSpark->m_vVel0.x  = pParticle->m_vVel.x * 0.25f + cosf(fRand1) * sinf(fRand2);
  911.                     pSpark->m_vVel0.z  = pParticle->m_vVel.z * 0.25f + sinf(fRand1) * sinf(fRand2);
  912.                     pSpark->m_vVel0.y  = cosf(fRand2);
  913.                     pSpark->m_vVel0.y *= ((FLOAT)rand()/(FLOAT)RAND_MAX) * 1.5f;
  914.  
  915.                     pSpark->m_vPos = pSpark->m_vPos0;
  916.                     pSpark->m_vVel = pSpark->m_vVel0;
  917.  
  918.                     D3DXColorLerp( &pSpark->m_clrDiffuse, &pParticle->m_clrFade,
  919.                                    &pParticle->m_clrDiffuse, pParticle->m_fFade );
  920.                     pSpark->m_clrFade = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
  921.                     pSpark->m_fFade   = 1.0f;
  922.                     pSpark->m_fTime0  = fTime;
  923.                 }
  924.             }
  925.  
  926.             // Kill particle
  927.             *ppParticle = pParticle->m_pNext;
  928.             pParticle->m_pNext = m_pParticlesFree;
  929.             m_pParticlesFree = pParticle;
  930.  
  931.             if(!pParticle->m_bSpark)
  932.                 m_dwParticles--;
  933.         }
  934.         else
  935.         {
  936.             ppParticle = &pParticle->m_pNext;
  937.         }
  938.     }
  939.  
  940.     // Emit new particles
  941.     DWORD dwParticlesEmit = m_dwParticles + dwNumParticlesToEmit;
  942.     while( m_dwParticles < m_dwParticlesLim && m_dwParticles < dwParticlesEmit )
  943.     {
  944.         if( m_pParticlesFree )
  945.         {
  946.             pParticle = m_pParticlesFree;
  947.             m_pParticlesFree = pParticle->m_pNext;
  948.         }
  949.         else
  950.         {
  951.             if( NULL == ( pParticle = new PARTICLE ) )
  952.                 return E_OUTOFMEMORY;
  953.         }
  954.  
  955.         pParticle->m_pNext = m_pParticles;
  956.         m_pParticles = pParticle;
  957.         m_dwParticles++;
  958.  
  959.         // Emit new particle
  960.         FLOAT fRand1 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 2.0f;
  961.         FLOAT fRand2 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 0.25f;
  962.  
  963.         pParticle->m_bSpark = FALSE;
  964.  
  965.         pParticle->m_vPos0 = vPosition + D3DXVECTOR3( 0.0f, m_fRadius, 0.0f );
  966.  
  967.         pParticle->m_vVel0.x  = cosf(fRand1) * sinf(fRand2) * 2.5f;
  968.         pParticle->m_vVel0.z  = sinf(fRand1) * sinf(fRand2) * 2.5f;
  969.         pParticle->m_vVel0.y  = cosf(fRand2);
  970.         pParticle->m_vVel0.y *= ((FLOAT)rand()/(FLOAT)RAND_MAX) * fEmitVel;
  971.  
  972.         pParticle->m_vPos = pParticle->m_vPos0;
  973.         pParticle->m_vVel = pParticle->m_vVel0;
  974.  
  975.         pParticle->m_clrDiffuse = clrEmitColor;
  976.         pParticle->m_clrFade    = clrFadeColor;
  977.         pParticle->m_fFade      = 1.0f;
  978.         pParticle->m_fTime0     = fTime;
  979.     }
  980.  
  981.     return S_OK;
  982. }
  983.  
  984.  
  985.  
  986.  
  987. //-----------------------------------------------------------------------------
  988. // Name: Render()
  989. // Desc: Renders the particle system using either pointsprites (if supported)
  990. //       or using 4 vertices per particle
  991. //-----------------------------------------------------------------------------
  992. HRESULT CParticleSystem::Render( LPDIRECT3DDEVICE8 pd3dDevice )
  993. {
  994.     HRESULT hr;
  995.  
  996.     // Set the render states for using point sprites
  997.     pd3dDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, TRUE );
  998.     pd3dDevice->SetRenderState( D3DRS_POINTSCALEENABLE,  TRUE );
  999.     pd3dDevice->SetRenderState( D3DRS_POINTSIZE,     FtoDW(0.08f) );
  1000.     pd3dDevice->SetRenderState( D3DRS_POINTSIZE_MIN, FtoDW(0.00f) );
  1001.     pd3dDevice->SetRenderState( D3DRS_POINTSCALE_A,  FtoDW(0.00f) );
  1002.     pd3dDevice->SetRenderState( D3DRS_POINTSCALE_B,  FtoDW(0.00f) );
  1003.     pd3dDevice->SetRenderState( D3DRS_POINTSCALE_C,  FtoDW(1.00f) );
  1004.  
  1005.     // Set up the vertex buffer to be rendered
  1006.     pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(POINTVERTEX) );
  1007.     pd3dDevice->SetVertexShader( D3DFVF_POINTVERTEX );
  1008.  
  1009.     PARTICLE*    pParticle = m_pParticles;
  1010.     POINTVERTEX* pVertices;
  1011.     DWORD        dwNumParticlesToRender = 0;
  1012.  
  1013.  
  1014.  
  1015.     // Lock the vertex buffer.  We fill the vertex buffer in small
  1016.     // chunks, using D3DLOCK_NOOVERWRITE.  When we are done filling
  1017.     // each chunk, we call DrawPrim, and lock the next chunk.  When
  1018.     // we run out of space in the vertex buffer, we start over at
  1019.     // the beginning, using D3DLOCK_DISCARD.
  1020.  
  1021.     m_dwBase += m_dwFlush;
  1022.  
  1023.     if(m_dwBase >= m_dwDiscard)
  1024.         m_dwBase = 0;
  1025.  
  1026.     if(FAILED(hr = m_pVB->Lock(m_dwBase * sizeof(POINTVERTEX), m_dwFlush * sizeof(POINTVERTEX),
  1027.         (BYTE **) &pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD)))
  1028.     {
  1029.         return hr;
  1030.     }
  1031.  
  1032.         
  1033.  
  1034.     // Render each particle
  1035.     while( pParticle )
  1036.     {
  1037.         D3DXVECTOR3 vPos(pParticle->m_vPos);
  1038.         D3DXVECTOR3 vVel(pParticle->m_vVel);
  1039.         FLOAT       fLengthSq = D3DXVec3LengthSq(&vVel);
  1040.         UINT        dwSteps;
  1041.  
  1042.         if( fLengthSq < 1.0f )        dwSteps = 2;
  1043.         else if( fLengthSq <  4.00f ) dwSteps = 3;
  1044.         else if( fLengthSq <  9.00f ) dwSteps = 4;
  1045.         else if( fLengthSq < 12.25f ) dwSteps = 5;
  1046.         else if( fLengthSq < 16.00f ) dwSteps = 6;
  1047.         else if( fLengthSq < 20.25f ) dwSteps = 7;
  1048.         else                          dwSteps = 8;
  1049.  
  1050.         vVel *= -0.04f / (FLOAT)dwSteps;
  1051.  
  1052.         D3DXCOLOR clrDiffuse;
  1053.         D3DXColorLerp(&clrDiffuse, &pParticle->m_clrFade, &pParticle->m_clrDiffuse, pParticle->m_fFade);
  1054.         DWORD dwDiffuse = (DWORD) clrDiffuse;
  1055.  
  1056.         // Render each particle a bunch of times to get a blurring effect
  1057.         for( DWORD i = 0; i < dwSteps; i++ )
  1058.         {
  1059.             pVertices->v     = vPos;
  1060.             pVertices->color = dwDiffuse;
  1061.             pVertices++;
  1062.  
  1063.             if( ++dwNumParticlesToRender == m_dwFlush )
  1064.             {
  1065.                 // Done filling this chunk of the vertex buffer.  Lets unlock and
  1066.                 // draw this portion so we can begin filling the next chunk.
  1067.  
  1068.                 m_pVB->Unlock();
  1069.  
  1070.                 if(FAILED(hr = pd3dDevice->DrawPrimitive( D3DPT_POINTLIST, m_dwBase, dwNumParticlesToRender)))
  1071.                     return hr;
  1072.  
  1073.                 // Lock the next chunk of the vertex buffer.  If we are at the 
  1074.                 // end of the vertex buffer, DISCARD the vertex buffer and start
  1075.                 // at the beginning.  Otherwise, specify NOOVERWRITE, so we can
  1076.                 // continue filling the VB while the previous chunk is drawing.
  1077.                 m_dwBase += m_dwFlush;
  1078.  
  1079.                 if(m_dwBase >= m_dwDiscard)
  1080.                     m_dwBase = 0;
  1081.  
  1082.                 if(FAILED(hr = m_pVB->Lock(m_dwBase * sizeof(POINTVERTEX), m_dwFlush * sizeof(POINTVERTEX),
  1083.                     (BYTE **) &pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD)))
  1084.                 {
  1085.                     return hr;
  1086.                 }
  1087.  
  1088.                 dwNumParticlesToRender = 0;
  1089.             }
  1090.  
  1091.             vPos += vVel;
  1092.         }
  1093.  
  1094.         pParticle = pParticle->m_pNext;
  1095.     }
  1096.  
  1097.     // Unlock the vertex buffer
  1098.     m_pVB->Unlock();
  1099.  
  1100.     // Render any remaining particles
  1101.     if( dwNumParticlesToRender )
  1102.     {
  1103.         if(FAILED(hr = pd3dDevice->DrawPrimitive( D3DPT_POINTLIST, m_dwBase, dwNumParticlesToRender )))
  1104.             return hr;
  1105.     }
  1106.  
  1107.     // Reset render states
  1108.     pd3dDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, FALSE );
  1109.     pd3dDevice->SetRenderState( D3DRS_POINTSCALEENABLE,  FALSE );
  1110.  
  1111.     return S_OK;
  1112. }
  1113.  
  1114.